package com.nowcoder.topic.dp.middle;

import java.util.ArrayList;

/**
 * NC327 取数游戏
 * @author d3y1
 */
public class NC327{
    private int result;

    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param A int整型ArrayList
     * @param B int整型ArrayList
     * @return int整型
     */
    public int numbergame (ArrayList<Integer> A, ArrayList<Integer> B) {
        // return solution1(A, B);
        return solution2(A, B);
    }

    /**
     * dfs: 遍历空间: 超时
     * @param A
     * @param B
     * @return
     */
    private int solution1(ArrayList<Integer> A, ArrayList<Integer> B){
        int n = A.size();

        dfs(A, B, 0, n-1, 0, 0, 0);

        return result;
    }

    /**
     * dfs: 递归
     * @param A
     * @param B
     * @param left
     * @param right
     * @param direction
     * @param sum
     * @param index
     */
    private void dfs(ArrayList<Integer> A, ArrayList<Integer> B, int left, int right, int direction, int sum, int index){
        if(direction == 1){
            sum += A.get(left) * B.get(index);
            left++;
            index++;
            if(left > right){
                result = Math.max(result, sum);
                return;
            }
        }
        if(direction == -1){
            sum += A.get(right) * B.get(index);
            right--;
            index++;
            if(left > right){
                result = Math.max(result, sum);
                return;
            }
        }

        dfs(A, B, left, right, 1, sum, index);
        dfs(A, B, left, right, -1, sum, index);
    }

    /**
     * 动态规划
     *
     * dp[i][j]表示区间[i,j]可以取得的最大价值
     *
     * len表示区间[i,j]长度, 亦即剩余取数次数(总共n次)
     * len = j-i+1
     *
     * n-len表示下次取数时对应的价值索引(0到n-1, 递增)
     *
     *            { A.get(i)*B.get(n-len)                                                         , i=j
     * dp[i][j] = {
     *            { Math.max(dp[i+1][j]+A.get(i)*B.get(n-len), dp[i][j-1]+A.get(j)*B.get(n-len))  , i<j
     *
     * @param A
     * @param B
     * @return
     */
    private int solution2(ArrayList<Integer> A, ArrayList<Integer> B){
        int n = A.size();

        int[][] dp = new int[n][n];

        int len;
        // 左边界i 降序
        for(int i=n-1; i>=0; i--){
            // 右边界j 升序
            for(int j=i; j<n; j++){
                len = j-i+1;
                if(i == j){
                    dp[i][j] = A.get(i)*B.get(n-len);
                }else{
                    // dp[i+1][j]+A.get(i)*B.get(n-len) 左边界i依赖于后面i+1(i<-i+1) 所以i应降序
                    // dp[i][j-1]+A.get(j)*B.get(n-len) 右边界j依赖于前面j-1(j-1->j) 所以j应升序
                    dp[i][j] = Math.max(dp[i+1][j]+A.get(i)*B.get(n-len), dp[i][j-1]+A.get(j)*B.get(n-len));
                }
            }
        }

        return dp[0][n-1];
    }
}